package com.slyak.spring.jpa;

import java.io.IOException;
import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource;

import spring.data.jpa.freemarker.FreemarkerResourceContext;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;

/**
 * <p> freemarker 模板渲染器，根据查询名称和模板文件获取相应的SQL
 *
 * @author stormning
 * @version V1.0, 2015/8/10.
 * wangjie modified on 2019/9/17 .
 */
public class FreemarkerSqlTemplates {

    private Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);

    private StringTemplateLoader sqlTemplateLoader = new StringTemplateLoader();

    private final Log logger = LogFactory.getLog(getClass());

    private String encoding = "UTF-8";

    private NamedTemplateResolver suffixResolver;

    private FreemarkerResourceContext freemarkerResourceContext;

    private static Map<String, FreemarkerSqlTemplates> sqlTemplateCache = new ConcurrentHashMap<>();

    public String process(String[] fileNames, String queryName, Object model) {
        loadPatternResource(fileNames);
        for (String name : fileNames) {
            try {
                StringWriter writer = new StringWriter();
                cfg.getTemplate(getTemplateKey(name, queryName), encoding).process(model, writer);
                return writer.toString();
            } catch (Exception e) {
                logger.error("process template error. Template name: " + name + " queryName:" + queryName, e);
            }
        }
        return StringUtils.EMPTY;
    }

    private String getTemplateKey(String entityName, String methodName) {
        return entityName + ":" + methodName;
    }

    public FreemarkerSqlTemplates(NamedTemplateResolver resolver, FreemarkerResourceContext context) {
        cfg.setTemplateLoader(sqlTemplateLoader);

        this.suffixResolver = resolver;
        this.freemarkerResourceContext = context;
    }

    public static void addTemplate(String key, NamedTemplateResolver resolver, FreemarkerResourceContext context) {
        sqlTemplateCache.computeIfAbsent(key, v -> new FreemarkerSqlTemplates(resolver, context));
    }

    public static FreemarkerSqlTemplates getTemplate(String key) {
        return sqlTemplateCache.get(key);
    }

    /**  
     * 设置suffixResolver  
     * @param suffixResolver
     */
    public void setSuffixResolver(NamedTemplateResolver suffixResolver) {
        this.suffixResolver = suffixResolver;
    }

    private void loadPatternResource(String... names) {
        List<Resource> reloadResourceList = null;
        try {
            reloadResourceList = freemarkerResourceContext.reloadAble(names);
        } catch (IOException e) {
            logger.error("try to reload template exception", e);
            return;
        }
        for (Resource re : reloadResourceList) {
            Map<String, String> sqlNamedMap = suffixResolver.doInTemplateResource(re);
            for (Entry<String, String> entry : sqlNamedMap.entrySet()) {
                String key = getTemplateKey(re.getFilename(), entry.getKey());
                Object src = sqlTemplateLoader.findTemplateSource(key);
                if (src != null) {
                    logger.warn("found duplicate template key, will replace the value, key:" + key);
                }
                sqlTemplateLoader.putTemplate(key, entry.getValue());
            }
        }
    }

}
